package com.ssy.lingxi.member.merchant.serviceimpl.paas;

import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MenuButtonDeleteVO;
import com.ssy.lingxi.member.merchant.api.model.vo.paas.MenuButtonVO;
import com.ssy.lingxi.member.merchant.entity.MenuButtonDO;
import com.ssy.lingxi.member.merchant.entity.MenuDO;
import com.ssy.lingxi.member.merchant.repository.MenuButtonRepository;
import com.ssy.lingxi.member.merchant.repository.MenuRepository;
import com.ssy.lingxi.member.merchant.service.paas.IBasePaasService;
import com.ssy.lingxi.member.merchant.service.paas.IPaasMenuService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 业务平台 - 菜单服务接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2020-06-15
 */
@Service
public class PaasMenuServiceImpl implements IPaasMenuService {
    @Resource
    private MenuRepository menuRepository;

    @Resource
    private MenuButtonRepository menuButtonRepository;

    @Resource
    private IBasePaasService basePaasService;

    /**
     * 新增菜单
     *
     * @param addVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> addMenu(MenuButtonVO addVO) {
        //判断菜单Url是否存在
        if(menuRepository.existsByUrlAndSource(addVO.getUrl(), addVO.getSource())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_URL_EXISTS);
        }

        //查找上级菜单
        MenuDO parentMenu = null;
        if(NumberUtil.notNullOrZero(addVO.getParentId())) {
            parentMenu = menuRepository.findFirstByPaasId(addVO.getParentId());
            if(parentMenu == null) {
                return Wrapper.fail(ResponseCode.MC_MS_PARENT_MENU_NOT_EXISTS);
            }
        }

        MenuDO menuDO = new MenuDO();
        menuDO.setPaasId(addVO.getPaasId());
        menuDO.setParentId(parentMenu == null ? 0L : parentMenu.getId());
        menuDO.setUrl(addVO.getUrl());
        menuDO.setTitle(addVO.getTitle());
        menuDO.setCode(addVO.getCode());
        menuDO.setUp(addVO.getUp());
        menuDO.setOrder(addVO.getOrder());
        menuDO.setDisabled(!addVO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()));
        menuDO.setSource(addVO.getSource());
        menuDO.setDataAuthConfig(addVO.getDataAuthConfig());
        menuDO.setAttrs(addVO.getAttrs() == null ? new HashMap<>() : addVO.getAttrs());
        menuDO.setRemark(StringUtils.hasLength(addVO.getRemark()) ? addVO.getRemark() : "");
        menuDO.setLevel(parentMenu == null ? 0 : parentMenu.getLevel() + 1);
        menuDO.setKey("");

        List<MenuButtonDO> buttonList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(addVO.getButtons())) {
            buttonList = addVO.getButtons().stream().map(b -> {
                MenuButtonDO buttonDO = new MenuButtonDO();
                buttonDO.setPaasId(b.getPaasId());
                buttonDO.setParentId(menuDO.getPaasId());
                buttonDO.setName(b.getName());
                buttonDO.setUrl(b.getUrl());
                buttonDO.setRemark(b.getRemark());
                buttonDO.setCode(b.getCode());
                buttonDO.setAttrs(b.getAttrs() == null ? new HashMap<>() : b.getAttrs());
                buttonDO.setKey("");
                return buttonDO;
            }).collect(Collectors.toList());
            menuButtonRepository.saveAll(buttonList);
        }

        menuDO.setButtons(new HashSet<>(buttonList));
        menuRepository.saveAndFlush(menuDO);

        return Wrapper.success();
    }

    /**
     * 修改菜单
     *
     * @param updateVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> updateMenu(MenuButtonVO updateVO) {
        //判断菜单Url是否存在
        if(menuRepository.existsByUrlAndSourceAndPaasIdNot(updateVO.getUrl(), updateVO.getSource(), updateVO.getPaasId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_URL_EXISTS);
        }

        //查找要修改的菜单
        MenuDO menuDO = menuRepository.findFirstByPaasId(updateVO.getPaasId());
        if(menuDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        //查找上级菜单
        MenuDO parentMenu = null;
        if(NumberUtil.notNullOrZero(updateVO.getParentId())) {
            parentMenu = menuRepository.findFirstByPaasId(updateVO.getParentId());
            if(parentMenu == null) {
                return Wrapper.fail(ResponseCode.MC_MS_PARENT_MENU_NOT_EXISTS);
            }
        }

        Integer oldAuthConfig = menuDO.getDataAuthConfig() == null ? 0 : menuDO.getDataAuthConfig();

        menuDO.setPaasId(updateVO.getPaasId());
        menuDO.setParentId(parentMenu == null ? 0L : parentMenu.getId());
        menuDO.setUrl(updateVO.getUrl());
        menuDO.setTitle(updateVO.getTitle());
        menuDO.setCode(updateVO.getCode());
        menuDO.setUp(updateVO.getUp());
        menuDO.setOrder(updateVO.getOrder());
        menuDO.setDisabled(!updateVO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()));
        menuDO.setSource(updateVO.getSource());
        menuDO.setDataAuthConfig(updateVO.getDataAuthConfig());
        menuDO.setAttrs(updateVO.getAttrs() == null ? new HashMap<>() : updateVO.getAttrs());
        menuDO.setRemark(StringUtils.hasLength(updateVO.getRemark()) ? updateVO.getRemark() : "");
        menuDO.setLevel(parentMenu == null ? 0 : parentMenu.getLevel() + 1);
        menuDO.setKey("");

        if(!CollectionUtils.isEmpty(menuDO.getButtons())) {
            menuButtonRepository.deleteAll(menuDO.getButtons());
        }

        List<MenuButtonDO> buttonList = new ArrayList<>();
        if(!CollectionUtils.isEmpty(updateVO.getButtons())) {
            buttonList = updateVO.getButtons().stream().map(b -> {
                MenuButtonDO buttonDO = new MenuButtonDO();
                buttonDO.setPaasId(b.getPaasId());
                buttonDO.setParentId(menuDO.getPaasId());
                buttonDO.setName(b.getName());
                buttonDO.setUrl(b.getUrl());
                buttonDO.setRemark(b.getRemark());
                buttonDO.setKey("");
                buttonDO.setCode(b.getCode());
                buttonDO.setAttrs(b.getAttrs() == null ? new HashMap<>() : b.getAttrs());
                return buttonDO;
            }).collect(Collectors.toList());
            menuButtonRepository.saveAll(buttonList);
        }

        menuDO.setButtons(new HashSet<>(buttonList));
        menuRepository.saveAndFlush(menuDO);

        //当不可配置数据权限时，删除已有的数据权限
        if(!oldAuthConfig.equals(EnableDisableStatus.DISABLE.getCode()) && menuDO.getDataAuthConfig().equals(EnableDisableStatus.DISABLE.getCode())) {
            basePaasService.removeDataAuthAsync(menuDO.getId(), menuDO.getUrl(), menuDO.getSource());
        }

        return Wrapper.success();
    }

//    /**
//     * 新增或修改菜单及其关联按钮（首先根据order生成key，如果已经存在，则顺序查找生成）
//     * @param menuVO 接口参数
//     * @return 操作结果
//     */
//    @Deprecated
//    @Transactional(rollbackFor = BusinessException.class)
//    @Override
//    public Wrapper<Void> updateOrInsertMenu(MenuButtonVO menuVO) {
//        List<MenuDO> menuDOList = menuRepository.findAll();
//
//        //判断菜单是否包含了其他菜单的按钮
//        List<MenuButtonDO> buttonDOList = menuDOList.stream().filter(m -> !m.getPaasId().equals(menuVO.getPaasId())).flatMap(m -> m.getButtons().stream()).collect(Collectors.toList());
//        if(!CollectionUtils.isEmpty(menuVO.getButtons()) && menuVO.getButtons().stream().anyMatch(b -> buttonDOList.stream().anyMatch(button -> button.getPaasId().equals(b.getPaasId())))) {
//            return Wrapper.fail(ResponseCode.MC_MS_BUTTON_ID_OR_NAME_EXISTS);
//        }
//
//        Integer oldAuthConfig = 0;
//        Long oldPassId;
//        MenuDO menuDO = menuDOList.stream().filter(m -> m.getPaasId().equals(menuVO.getPaasId())).findFirst().orElse(null);
//        boolean isUpdate = true;
//        if(menuDO == null) {
//            menuDO = new MenuDO();
//            isUpdate = false;
//            oldPassId = 0L;
//        } else {
//            oldPassId = menuDO.getPaasId();
//            oldAuthConfig = menuDO.getDataAuthConfig() == null ? 0 : menuDO.getDataAuthConfig();
//        }
//
//        //同级菜单顺序加1
//        List<MenuDO> sameLevelList;
//        if(isUpdate) {
//            MenuDO finalMenuDo1 = menuDO;
//            sameLevelList = menuDOList.stream().filter(m -> !m.getId().equals(finalMenuDo1.getId()) && m.getParentId().equals(menuVO.getParentId()) && m.getSource().equals(menuVO.getSource()) && m.getOrder() >= menuVO.getOrder()).sorted(Comparator.comparingInt(MenuDO::getOrder)).collect(Collectors.toList());
//        } else {
//            sameLevelList = menuDOList.stream().filter(m -> m.getParentId().equals(menuVO.getParentId()) && m.getSource().equals(menuVO.getSource()) && m.getOrder() >= menuVO.getOrder()).sorted(Comparator.comparingInt(MenuDO::getOrder)).collect(Collectors.toList());
//        }
//
//        if(!CollectionUtils.isEmpty(sameLevelList)) {
//            Integer minOrder = Collections.min(sameLevelList.stream().map(MenuDO::getOrder).collect(Collectors.toList()));
//            if(minOrder.equals(menuVO.getOrder())) {
//                int newOrder = menuVO.getOrder();
//                for (MenuDO aDo : sameLevelList) {
//                    newOrder = newOrder + 1;
//                    aDo.setOrder(newOrder);
//                }
//                menuRepository.saveAll(sameLevelList);
//            }
//        }
//
//        menuDO.setPaasId(menuVO.getPaasId());
//        menuDO.setParentId(menuVO.getParentId());
//        menuDO.setRemark(StringUtils.hasLength(menuVO.getRemark()) ? menuVO.getRemark() : "");
//        menuDO.setUrl(menuVO.getUrl());
//        menuDO.setTitle(menuVO.getTitle());
//        menuDO.setCode(menuVO.getCode());
//        menuDO.setUp(menuVO.getUp());
//        menuDO.setOrder(menuVO.getOrder());
//        menuDO.setDisabled(!menuVO.getStatus().equals(EnableDisableStatus.ENABLE.getCode()));
//        menuDO.setSource(menuVO.getSource());
//        menuDO.setDataAuthConfig(menuVO.getDataAuthConfig());
//        menuDO.setAttrs(menuVO.getAttrs() == null ? new HashMap<>() : menuVO.getAttrs());
//        String menuKey;
//        String keyPrefix;
//        int level;
//        if(menuVO.getParentId().equals(0L)) {
//            level = 1;
//            menuKey = menuVO.getOrder().toString();
//            keyPrefix = "";
//        } else {
//            MenuDO upperMenuDO = menuDOList.stream().filter(m -> m.getPaasId().equals(menuVO.getParentId())).findFirst().orElse(null);
//            if(upperMenuDO == null) {
//                return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
//            }
//
//            level = upperMenuDO.getLevel() + 1;
//            keyPrefix = upperMenuDO.getKey();
//            menuKey = upperMenuDO.getKey().concat("-").concat(menuVO.getOrder().toString());
//        }
//
//        List<String> subKeyList = menuDOList.stream().filter(m -> !m.getPaasId().equals(oldPassId) && m.getLevel().equals(level) && m.getKey().startsWith(keyPrefix)).map(MenuDO::getKey).collect(Collectors.toList());
//        if(subKeyList.contains(menuKey)) {
//            int order = 1;
//            while (true) {
//                menuKey = StringUtils.hasLength(keyPrefix) ? keyPrefix + "-" + order :  String.valueOf(order);
//                if (!subKeyList.contains(menuKey)) {
//                    break;
//                }
//                order++;
//            }
//        }
//
//        menuDO.setLevel(level);
//        menuDO.setKey(menuKey);
//
//        if(isUpdate && !CollectionUtils.isEmpty(menuDO.getButtons())) {
//            menuButtonRepository.deleteAll(menuDO.getButtons());
//        }
//
//        List<MenuButtonDO> buttonList = new ArrayList<>();
//        if(!CollectionUtils.isEmpty(menuVO.getButtons())) {
//            MenuDO finalMenuDO = menuDO;
//            String finalMenuKey = menuKey;
//            buttonList = menuVO.getButtons().stream().map(b -> {
//                MenuButtonDO buttonDO = new MenuButtonDO();
//                buttonDO.setPaasId(b.getPaasId());
//                buttonDO.setParentId(finalMenuDO.getPaasId());
//                buttonDO.setName(b.getName());
//                buttonDO.setUrl(b.getUrl());
//                buttonDO.setRemark(b.getRemark());
//                buttonDO.setKey(finalMenuKey);
//                buttonDO.setCode(b.getCode());
//                buttonDO.setAttrs(b.getAttrs() == null ? new HashMap<>() : b.getAttrs());
//                return buttonDO;
//            }).collect(Collectors.toList());
//            menuButtonRepository.saveAll(buttonList);
//        }
//
//        menuDO.setButtons(new HashSet<>(buttonList));
//        menuRepository.saveAndFlush(menuDO);
//
//        //当不可配置数据权限时，删除已有的数据权限
//        if(oldAuthConfig.equals(EnableDisableStatus.ENABLE.getCode()) && menuDO.getDataAuthConfig().equals(EnableDisableStatus.DISABLE.getCode())) {
//            basePaasService.removeDataAuthAsync(menuDO.getId(), menuDO.getUrl(), menuDO.getSource());
//        }
//
//        return Wrapper.success();
//    }

    /**
     * 删除菜单
     * @param menuVO 接口参数
     * @return 删除结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> deleteMenu(MenuButtonDeleteVO menuVO) {
        MenuDO menuDO = menuRepository.findFirstByPaasId(menuVO.getPaasId());
        if(menuDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MENU_DOES_NOT_EXIST);
        }

        //删除已有的数据权限
        basePaasService.removeDataAuthAsync(menuDO.getId(), menuDO.getUrl(), menuDO.getSource());

        menuRepository.delete(menuDO);

        return Wrapper.success();
    }
}
